package mylayers

import (
	"fmt"
	"github.com/google/gopacket"
	"net"
	"time"
)

type mysqlMessage struct {
	start int
	end   int

	ts             time.Time
	isRequest      bool
	packetLength   uint32
	seq            uint8
	typ            uint8
	numberOfRows   int
	numberOfFields int
	size           uint64
	fields         []string
	rows           [][]string
	tables         string
	isOK           bool
	affectedRows   uint64
	insertID       uint64
	isError        bool
	errorCode      uint16
	errorInfo      string
	query          string
	ignoreMessage  bool

	direction    uint8
	isTruncated  bool
	tcpTuple     TCPTuple
	cmdlineTuple *CmdlineTuple
	raw          []byte
	notes        []string
}

// Source and destination process names, as found by the proc module.
type CmdlineTuple struct {
	Src, Dst []byte
}

const MaxTCPTupleRawSize = 16 + 16 + 2 + 2 + 4

type HashableTCPTuple [MaxTCPTupleRawSize]byte

type TCPTuple struct {
	IPLength         int
	SrcIP, DstIP     net.IP
	SrcPort, DstPort uint16
	StreamID         uint32

	raw HashableTCPTuple // Src_ip:Src_port:Dst_ip:Dst_port:stream_id
}

type mysqlStream struct {
	data []byte

	parseOffset int
	parseState  parseState
	isClient    bool

	//message *mysqlMessage
}

type parseState int

var MysqlLayerType = gopacket.RegisterLayerType(
	3300,
	gopacket.LayerTypeMetadata{
		"MysqlLayerType",
		gopacket.DecodeFunc(decodeMysqlStreamLayer),
	},
)

// When we inquire about the type, what type of layer should
// we say it is? We want it to return our custom layer type
func (l mysqlStream) LayerType() gopacket.LayerType {
	return MysqlLayerType
}

// LayerContents returns the information that our layer
// provides. In this case it is a header layer so
// we return the header information
func (l mysqlStream) LayerContents() []byte {
	return l.data
}

// LayerPayload returns the subsequent layer built
// on top of our layer or raw payload
func (l mysqlStream) LayerPayload() []byte {
	return l.data
}

// Custom decode function. We can name it whatever we want
// but it should have the same arguments and return value
// When the layer is registered we tell it to use this decode function
func decodeMysqlStreamLayer(data []byte, p gopacket.PacketBuilder) error {
	// AddLayer appends to the list of layers that the packet has
	fmt.Printf("%s\n", data)
	p.AddLayer(&mysqlStream{data[0:], int(data[1]), parseState(data[2]), bool(data[3])})

	// The return value tells the packet what layer to expect
	// with the rest of the data. It could be another header layer,
	// nothing, or a payload layer.

	// nil means this is the last layer. No more decoding
	// return nil

	// Returning another layer type tells it to decode
	// the next layer with that layer's decoder function
	// return p.NextDecoder(layers.LayerTypeEthernet)

	// Returning payload type means the rest of the data
	// is raw payload. It will set the application layer
	// contents with the payload
	return p.NextDecoder(gopacket.LayerTypePayload)
}
